// DiplomacyData.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;
using Supremacy.AI;
using Supremacy.Data;
using Supremacy.Game;
using Supremacy.Types;
using Supremacy.Utility;

namespace Supremacy.Diplomacy
{
    public interface IDiplomacyData
    {
        Meter Regard { get; }
        Meter Trust { get; }
        RegardLevel EffectiveRegard { get; }
    }

    public interface IDiplomacyDataExtended : IDiplomacyData
    {
        TurnNumber LastTotalWarAttack { get; }
        TurnNumber LastColdWarAttack { get; }
        TurnNumber LastIncursion { get; }
        IDiplomacyData BaseData { get; }
        IList<Motivation> Motivations { get; }
        Motivation CurrentMotivation { get; }
        InfluenceMap ThreatMap { get; }

        void ClearMotivations();
        void ConsiderMotivation(Motivation motivation);
        void SortMotivations();
        void OnAttack();
        void OnIncursion();
    }

    [Serializable]      
    public class DiplomacyData : IDiplomacyData
    {
        [NonSerialized]
        private static TableMap s_diplomacyTables;

        private readonly Meter _regard;
        private readonly Meter _trust;

        protected static TableMap DiplomacyTables
        {
            get
            {
                if (s_diplomacyTables == null)
                    s_diplomacyTables = GameContext.Current.Tables.DiplomacyTables;
                return s_diplomacyTables;
            }
        }

        public DiplomacyData()
        {
            _regard = new Meter(500, 0, 1000);
            _trust = new Meter(500, 0, 1000);
        }

        public Meter Regard
        {
            get { return _regard; }
        }

        public Meter Trust
        {
            get { return _trust; }
        }

        public RegardLevel EffectiveRegard
        {
            get { return CalculateRegardLevel(_regard.CurrentValue); }
        }

        public RegardLevel EffectiveTrust
        {
            get { return CalculateRegardLevel(_trust.CurrentValue); }
        }

        public static RegardLevel CalculateRegardLevel(int regard)
        {
            var regardLevels = DiplomacyTables["RegardLevels"];
            var regardLevel = RegardLevel.Detested;
            var lowerBounds = (from o in EnumHelper.GetValues<RegardLevel>()
                               let lowerBound = (regardLevels[o.ToString()] != null)
                                   ? Number.ParseInt32(regardLevels[o.ToString()][0].Trim())
                                   : -1
                               where (lowerBound >= 0) && (regard >= lowerBound)
                               orderby lowerBound descending
                               select new { Regard = o, LowerBound = lowerBound });
            if (lowerBounds.Any())
                regardLevel = lowerBounds.First().Regard;
            return regardLevel;
        }
    }

    [Serializable]
    public class DiplomacyDataInternal : IDiplomacyDataExtended
    {
        private readonly IDiplomacyData _baseData;
        private readonly List<Motivation> _motivations;
        private readonly InfluenceMap _threatMap;

        public TurnNumber LastTotalWarAttack { get; protected set; }
        public TurnNumber LastColdWarAttack { get; protected set; }
        public TurnNumber LastIncursion { get; protected set; }

        public DiplomacyDataInternal() 
        {
            _baseData = new DiplomacyData();
            _motivations = new List<Motivation>();
            _threatMap = new InfluenceMap();
        }

        public DiplomacyDataInternal(IDiplomacyData baseData)
        {
            if (baseData == null)
                throw new ArgumentNullException("baseData");
            _baseData = baseData;
        }

        #region IDiplomacyDataExtended Members
        public IDiplomacyData BaseData
        {
            get { return _baseData; }
        }

        public IList<Motivation> Motivations
        {
            get { return _motivations.AsReadOnly(); }
        }

        public Motivation CurrentMotivation
        {
            get
            {
                if (Motivations.Count > 0)
                    return Motivations[0];
                return Motivation.NoMotivation;
            }
        }

        public InfluenceMap ThreatMap
        {
            get { return _threatMap; }
        }

        public void ClearMotivations()
        {
            _motivations.Clear();
        }

        public void ConsiderMotivation(Motivation motivation)
        {
            if (motivation == null)
                throw new ArgumentNullException("motivation");
            _motivations.Add(motivation);
        }

        public void SortMotivations()
        {
            _motivations.Sort((a, b) => b.Priority.CompareTo(a.Priority));
        }

        public void OnAttack()
        {
            if (EffectiveRegard >= RegardLevel.ColdWar)
            {
                this.LastColdWarAttack = GameContext.Current.TurnNumber;
            }
            else if (EffectiveRegard <= RegardLevel.TotalWar)
            {
                this.LastTotalWarAttack = GameContext.Current.TurnNumber;
            }
        }

        public void OnIncursion()
        {
            this.LastIncursion = GameContext.Current.TurnNumber;
        }
        #endregion

        #region IDiplomacyData Members
        public Meter Regard
        {
            get { return _baseData.Regard; }
        }

        public Meter Trust
        {
            get { return _baseData.Trust; }
        }

        public RegardLevel EffectiveRegard
        {
            get { return _baseData.EffectiveRegard; }
        }
        #endregion
    }
}